package com.ikas.ai.server.module.machine.service;

import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ikas.ai.consts.MachineAndWorkConditionConst;
import com.ikas.ai.server.module.machine.model.dto.MachineAndSystemTreeDTO;
import com.ikas.ai.server.error.BusinessException;
import com.ikas.ai.server.module.equipment.dao.EquipmentDAO;
import com.ikas.ai.server.module.equipment.model.po.Equipment;
import com.ikas.ai.server.module.equipment.service.EquipmentService;
import com.ikas.ai.server.module.machine.dao.MachineDAO;
import com.ikas.ai.server.module.machine.dao.MachineSystemDAO;
import com.ikas.ai.server.module.machine.model.dto.MachineSystemAddDTO;
import com.ikas.ai.server.module.machine.model.dto.MachineSystemExcelDTO;
import com.ikas.ai.server.module.machine.model.dto.MachineSystemUpdateDTO;
import com.ikas.ai.server.module.machine.model.po.Machine;
import com.ikas.ai.server.module.machine.model.po.MachineSystem;
import com.ikas.ai.utils.CollectionUtil;
import com.ikas.ai.utils.EasyPoiUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 设备资产管理
 *
 * @author tang.xuandong
 * @version 1.0.0
 * @date 2023/2/1 10:41
 */
@Service
public class MachineSystemService extends ServiceImpl<MachineSystemDAO, MachineSystem> {

    /**
     * t_base_machine 机组
     */
    @Autowired
    private MachineDAO machineDAO;
    @Autowired
    private MachineService machineService;

    /**
     * t_base_machine_system 系统
     */
    @Autowired
    private MachineSystemDAO machineSystemDAO;
    @Autowired
    private MachineSystemService machineSystemService;

    /**
     * t_base_equipment 设备
     */
    @Resource
    private EquipmentService equipmentService;
    @Resource
    private EquipmentDAO equipmentDAO;


    private final String EXCEL_FILE_NAME = "设备树";

    public List<MachineSystem> pageQuerySystem(String machineNo, String systemName, String systemNo) {
        LambdaQueryChainWrapper<MachineSystem> lambdaQueryChainWrapper = new LambdaQueryChainWrapper<>(machineSystemDAO);
        return lambdaQueryChainWrapper
                .eq(StringUtils.isNotBlank(machineNo), MachineSystem::getMachineNo, machineNo)
                .like(StringUtils.isNotBlank(systemName), MachineSystem::getSystemName, systemName)
                .like(StringUtils.isNotBlank(systemNo), MachineSystem::getSystemNo, systemNo)
                .orderByDesc(MachineSystem::getId)
                .list();
    }

    public List<MachineSystem> getSystemList(String machineNo, String systemName, String systemNo) {
        LambdaQueryChainWrapper<MachineSystem> queryChainWrapper = new LambdaQueryChainWrapper<>(machineSystemDAO);
        return queryChainWrapper
                .like(StringUtils.isNotBlank(machineNo), MachineSystem::getMachineNo, machineNo)
                .like(StringUtils.isNotBlank(systemName), MachineSystem::getSystemName, systemName)
                .like(StringUtils.isNotBlank(systemNo), MachineSystem::getSystemNo, systemNo)
                .list();
    }

    public List<Machine> getMachineList(Integer type) {
        LambdaQueryChainWrapper<Machine> lambdaQueryChainWrapper = new LambdaQueryChainWrapper<>(machineDAO);
        if (Objects.isNull(type)) {
            return machineDAO.selectList(null);
        } else {
            return lambdaQueryChainWrapper.eq(Machine::getType, 1).list();
        }
    }

    public Boolean isDuplicateNo(String systemNo) {
        LambdaQueryChainWrapper<MachineSystem> lambdaQueryChainWrapper = new LambdaQueryChainWrapper<>(machineSystemDAO);
        return CollectionUtils.isNotEmpty(lambdaQueryChainWrapper.eq(MachineSystem::getSystemNo, systemNo).list());
    }

    public Set<MachineSystem> selectSystemBySystemNo(String systemNo) {
        LambdaQueryChainWrapper<MachineSystem> lambdaQueryChainWrapper = new LambdaQueryChainWrapper<>(machineSystemDAO);
        List<MachineSystem> list = lambdaQueryChainWrapper.eq(MachineSystem::getSystemNo, systemNo).list();
        return list.stream().filter(distinctByKey(MachineSystem::getSystemNo)).collect(Collectors.toSet());
    }

    public MachineSystem addMachineSystem(MachineSystemAddDTO machineSystemAddDTO, Long userId) {
        String reg = "/[\u4E00-\u9FA5]/";
        Pattern pattern = Pattern.compile(reg);
        pattern.matcher("111");
        //查询数据库是否有重名
        if (isDuplicateNo(machineSystemAddDTO.getSystemNo())) {
            throw new BusinessException("该系统编号已存在！");
        }
        MachineSystem machineSystem = new MachineSystem();
        BeanUtils.copyProperties(machineSystemAddDTO, machineSystem);
        machineSystem.setCreator(userId);
        machineSystem.setUpdater(userId);
        machineSystem.setCreateTime(new Date());
        machineSystem.setUpdateTime(new Date());
        save(machineSystem);
        return machineSystem;
    }

    public MachineSystem updateMachineSystem(MachineSystemUpdateDTO machineSystemUpdateDTO, Long userId) {
        Set<MachineSystem> machineSystems = selectSystemBySystemNo(machineSystemUpdateDTO.getSystemNo());
        Map<String, MachineSystem> machineSystemMap = machineSystems.stream().collect(Collectors.toMap(MachineSystem::getSystemNo, f -> f));
        String systemNo = machineSystemUpdateDTO.getSystemNo();
        if (machineSystemMap.containsKey(systemNo) && !machineSystemUpdateDTO.getId().equals(machineSystemMap.get(systemNo).getId())) {
            //系统存在该编号，并且不属于这个机组系统
            throw new BusinessException("该系统编号已存在");
        }
        MachineSystem machineSystem = machineSystemDAO.selectById(machineSystemUpdateDTO.getId());
        BeanUtils.copyProperties(machineSystemUpdateDTO, machineSystem);
        machineSystem.setUpdateTime(new Date());
        machineSystem.setUpdater(userId);
        updateById(machineSystem);

        return machineSystem;
    }

    @Transactional(rollbackFor = Exception.class)
    public int deleteMachineSystem(List<Long> machineSystemIds) {
        List<MachineSystem> machineSystems = machineSystemDAO.selectBatchIds(machineSystemIds);
        //删除系统中的设备
        LambdaQueryChainWrapper<Equipment> lambdaQueryChainWrapper = new LambdaQueryChainWrapper<>(equipmentDAO);

        List<Long> equipmentIds = lambdaQueryChainWrapper.in(Equipment::getSystemId, machineSystemIds).list().stream().map(Equipment::getId).collect(Collectors.toList());
        equipmentService.deleteEquipment(equipmentIds);
        if (!CollectionUtil.isEmpty(machineSystems)) {
            return machineSystemDAO.deleteBatchIds(machineSystemIds);
        }
        return 0;
    }

    @Transactional(rollbackFor = Exception.class)
    public void importMachineSystem(MultipartFile file, Long userId) throws Exception {
        machineSystemDAO.clearTable();
        equipmentDAO.clearTable();
        ImportParams params = new ImportParams();
        params.setStartSheetIndex(0);
        List<MachineSystemExcelDTO> list = ExcelImportUtil.importExcel(file.getInputStream(), MachineSystemExcelDTO.class, params);
        List<Machine> machineList = machineService.list();
        Map<String, Machine> machineMap = machineList.stream().collect(Collectors.toMap(Machine::getMachineNo, f -> f));
        List<MachineSystem> machineSystemList = list.stream().filter(bean -> bean.getMachineNo()!=null).map(item -> {
            MachineSystem machineSystem = new MachineSystem();
            BeanUtils.copyProperties(item, machineSystem);
            machineSystem.setMachineId(machineMap.get(item.getMachineNo()).getId());
            machineSystem.setCreateTime(new Date());
            machineSystem.setCreator(userId);
            machineSystem.setUpdateTime(new Date());
            machineSystem.setUpdater(userId);
            return machineSystem;
        }).filter(distinctByKey(bean -> bean.getMachineNo()+bean.getSystemNo())).collect(Collectors.toList());
        this.saveBatch(machineSystemList);

        Map<String, MachineSystem> machineSystemMap = machineSystemList.stream().collect(Collectors.toMap(bean -> bean.getMachineNo()+bean.getSystemNo(), f -> f));
        List<Equipment> equipmentList = list.stream().filter(bean->bean.getSystemNo()!=null).map(item -> {
            Equipment equipment = new Equipment();
            equipment.setEquipmentCode(item.getEquipmentCode());
            equipment.setEquipmentName(item.getEquipmentName());
            equipment.setSystemId(machineSystemMap.get(item.getMachineNo()+item.getSystemNo()).getId());
            equipment.setSystemNo(item.getSystemNo());
            equipment.setCreateTime(new Date());
            equipment.setUpdateTime(new Date());
            equipment.setCreator(userId);
            equipment.setUpdater(userId);
            return equipment;
        }).filter(distinctByKey(bean -> bean.getSystemId() + bean.getEquipmentCode())).collect(Collectors.toList());
        equipmentService.saveBatch(equipmentList);
    }


    public void exportMachineSystem(HttpServletResponse response){
        Map<Long, List<MachineSystem>> machineSystemChecker = machineSystemService.list().stream().collect(Collectors.groupingBy(MachineSystem::getId));
        List<MachineSystemExcelDTO> excelCollect = equipmentService.list().stream().map(equipment -> {
                    List<MachineSystem> machineSystems = machineSystemChecker.get(equipment.getSystemId());
                    MachineSystemExcelDTO machineSystemExcelDTO = new MachineSystemExcelDTO();
                    if (!CollectionUtil.isEmpty(machineSystems)) {
                        MachineSystem machineSystem = machineSystems.get(0);
                        machineSystemExcelDTO.setMachineNo(machineSystem.getMachineNo());
                        machineSystemExcelDTO.setSystemNo(machineSystem.getSystemNo());
                        machineSystemExcelDTO.setSystemName(machineSystem.getSystemName());
                        machineSystemExcelDTO.setEquipmentCode(equipment.getEquipmentCode());
                        machineSystemExcelDTO.setEquipmentName(equipment.getEquipmentName());
                    }
                    return machineSystemExcelDTO;
                }).filter(machineSystemExcelDTO -> machineSystemExcelDTO.getMachineNo() != null)
                .collect(Collectors.toList());
        EasyPoiUtil.exportExcel(excelCollect,null,EXCEL_FILE_NAME, MachineSystemExcelDTO.class,EXCEL_FILE_NAME+".xlsx",true,response);
    }

    public MachineAndSystemTreeDTO getMachineAndSystemTree(String machineNo){
        List<MachineSystem> machineSystemList = machineSystemService.list(
                new LambdaQueryWrapper<MachineSystem>().eq(MachineSystem::getMachineNo, machineNo)
        );
        if (CollectionUtil.isEmpty(machineSystemList)||machineNo.equals(MachineAndWorkConditionConst.COMMON_MACHINE_NO)) {
            throw new BusinessException("传入的MachineNo找不到匹配项或者传入了UCOMMON");
        }
        Map<Long, List<Equipment>> equipmentChecker = equipmentService.list().stream().collect(Collectors.groupingBy(Equipment::getSystemId));
        Machine one = machineService.getOne(
                new LambdaQueryWrapper<Machine>().eq(Machine::getMachineNo, machineNo)
        );
        List<MachineAndSystemTreeDTO> systemChildren = machineSystemList.stream().map(machineSystem -> {
            MachineAndSystemTreeDTO systemTreeNode = new MachineAndSystemTreeDTO();
            systemTreeNode.setName(machineSystem.getSystemName());
            systemTreeNode.setLevel(1);
            systemTreeNode.setTableId(machineSystem.getId());
            systemTreeNode.setNodeType(MachineAndSystemTreeDTO.TYPE_SYSTEM);
            systemTreeNode.setParentCode(machineNo);
            systemTreeNode.setParentName(one.getMachineName());
            systemTreeNode.setCode(machineSystem.getSystemNo());
            List<Equipment> equipment = equipmentChecker.get(machineSystem.getId());
            List<MachineAndSystemTreeDTO> equipmentChildren = equipment.stream().map(equipmentChild -> {
                MachineAndSystemTreeDTO equipmentTreeNode = new MachineAndSystemTreeDTO();
                equipmentTreeNode.setName(equipmentChild.getEquipmentName());
                equipmentTreeNode.setCode(equipmentChild.getEquipmentCode());
                equipmentTreeNode.setLevel(2);
                equipmentTreeNode.setParentCode(machineSystem.getSystemName());
                equipmentTreeNode.setParentCode(machineSystem.getSystemNo());
                equipmentTreeNode.setTableId(equipmentChild.getId());
                equipmentTreeNode.setNodeType(MachineAndSystemTreeDTO.TYPE_EQUIPMENT);
                return equipmentTreeNode;
            }).collect(Collectors.toList());
            systemTreeNode.setChildren(equipmentChildren);
            systemTreeNode.setChildrenCount(equipmentChildren.size());
            return systemTreeNode;
        }).collect(Collectors.toList());
        MachineAndSystemTreeDTO rootNode = new MachineAndSystemTreeDTO()
                .setNodeType(MachineAndSystemTreeDTO.TYPE_MACHINE)
                .setCode(one.getMachineNo())
                .setLevel(0)
                .setName(one.getMachineName())
                .setChildrenCount(machineSystemList.size())
                .setTableId(one.getId())
                .setChildren(systemChildren)
                .setChildrenCount(systemChildren.size());
        return rootNode;
    }


    private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        Map<Object, Boolean> seen = new ConcurrentHashMap<>();
        return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
    }

    public static void main(String[] args) {
        String reg = "^[^\\u4e00-\\u9fa5]*$";
        Pattern pattern = Pattern.compile(reg);
        boolean matches = pattern.matcher("123").matches();
        System.out.println(matches);

    }
}
